home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / actionrp / lrogue0.1 / lrogue0 / rogue / machdep.c < prev    next >
C/C++ Source or Header  |  1992-09-28  |  17KB  |  594 lines

  1. #define _POSIX_SOURCE
  2. #define LINUX
  3. /*
  4.  * machdep.c
  5.  *
  6.  * This source herein may be modified and/or distributed by anybody who
  7.  * so desires, with the following restrictions:
  8.  *    1.)  No portion of this notice shall be removed.
  9.  *    2.)  Credit shall not be taken for the creation of this source.
  10.  *    3.)  This code is not to be traded, sold, or used for personal
  11.  *         gain or profit.
  12.  *
  13.  */
  14.  
  15. /* Included in this file are all system dependent routines.  Extensive use
  16.  * of #ifdef's will be used to compile the appropriate code on each system:
  17.  *
  18.  *    UNIX:        all UNIX systems.
  19.  *    UNIX_BSD4_2: UNIX BSD 4.2 and later, UTEK, (4.1 BSD too?)
  20.  *    UNIX_SYS5:   UNIX system 5
  21.  *    UNIX_V7:     UNIX version 7
  22.  *
  23.  * All UNIX code should be included between the single "#ifdef UNIX" at the
  24.  * top of this file, and the "#endif UNIX" at the bottom.
  25.  * 
  26.  * To change a routine to include a new UNIX system, simply #ifdef the
  27.  * existing routine, as in the following example:
  28.  *
  29.  *   To make a routine compatible with UNIX system 5, change the first
  30.  *   function to the second:
  31.  *
  32.  *      md_function()
  33.  *      {
  34.  *         code;
  35.  *      }
  36.  *
  37.  *      md_function()
  38.  *      {
  39.  *      #ifdef UNIX_SYS5
  40.  *         sys5code;
  41.  *      #else
  42.  *         code;
  43.  *      #endif
  44.  *      }
  45.  *
  46.  * Appropriate variations of this are of course acceptible.
  47.  * The use of "#elseif" is discouraged because of non-portability.
  48.  * If the correct #define doesn't exist, "UNIX_SYS5" in this case, make it up
  49.  * and insert it in the list at the top of the file.  Alter the CFLAGS
  50.  * in you Makefile appropriately.
  51.  *
  52.  */
  53.  
  54. #ifdef UNIX
  55.  
  56. #include <stdio.h>
  57. #include <sys/file.h>
  58. #include <sys/types.h>
  59. #include <sys/stat.h>
  60. #include <sys/time.h>
  61. #include <signal.h>
  62. #include "rogue.h"
  63.  
  64. #ifdef _POSIX_SOURCE
  65. #include <unistd.h>
  66. #include <termios.h>
  67. #endif _POSIX_SOURCE
  68.  
  69. /* md_slurp:
  70.  *
  71.  * This routine throws away all keyboard input that has not
  72.  * yet been read.  It is used to get rid of input that the user may have
  73.  * typed-ahead.
  74.  *
  75.  * This function is not necessary, so it may be stubbed.  The might cause
  76.  * message-line output to flash by because the game has continued to read
  77.  * input without waiting for the user to read the message.  Not such a
  78.  * big deal.
  79.  */
  80.  
  81. md_slurp()
  82. {
  83. #ifdef UNIX_BSD4_2
  84.     long ln;
  85.     int i, n;
  86.     ioctl(0, FIONREAD, &ln);
  87.     n = (int) (stdin->_cnt + ln);
  88.  
  89.     for (i = 0; i < n; i++) {
  90.         (void) getchar();
  91.     }
  92. #endif UNIX_BSD4_2
  93. }
  94.  
  95. /* md_control_keyboard():
  96.  *
  97.  * This routine is much like md_cbreak_no_echo_nonl() above.  It sets up the
  98.  * keyboard for appropriate input.  Specifically, it prevents the tty driver
  99.  * from stealing characters.  For example, ^Y is needed as a command
  100.  * character, but the tty driver intercepts it for another purpose.  Any
  101.  * such behavior should be stopped.  This routine could be avoided if
  102.  * we used RAW mode instead of CBREAK.  But RAW mode does not allow the
  103.  * generation of keyboard signals, which the program uses.
  104.  *
  105.  * The parameter 'mode' when true, indicates that the keyboard should
  106.  * be set up to play rogue.  When false, it should be restored if
  107.  * necessary.
  108.  *
  109.  * This routine is not strictly necessary and may be stubbed.  This may
  110.  * cause certain command characters to be unavailable.
  111.  */
  112.  
  113. md_control_keybord(mode)
  114. short mode;
  115. {
  116.     static boolean called_before = 0;
  117. #ifdef _POSIX_SOURCE
  118.         static struct termios tc_orig ;
  119.         static struct termios tc_temp ;
  120. #else
  121.     static struct ltchars ltc_orig;
  122.     static struct tchars tc_orig;
  123.     struct ltchars ltc_temp;
  124.     struct tchars tc_temp;
  125. #endif
  126.     signal(SIGTSTP,SIG_IGN);
  127.  
  128.     if (!called_before) {
  129.         called_before = 1;
  130. #ifdef _POSIX_SOURCE
  131.         tcgetattr(0,&tc_orig);    
  132. #else
  133.         ioctl(0, TIOCGETC, &tc_orig);
  134.         ioctl(0, TIOCGLTC, <c_orig);
  135. #endif
  136.     }
  137. #ifndef _POSIX_SOURCE
  138.     ltc_temp = ltc_orig;
  139. #endif _POSIX_SOURCE
  140.     tc_temp = tc_orig;
  141.  
  142.     if (!mode) {
  143. #ifdef _POSIX_SOURCE
  144.     /* tc_temp.c_cc[VSUSP] = -1; */
  145.     tc_temp.c_cc[VERASE] = -1;
  146.     tc_temp.c_cc[VSTART] = -1;
  147.     tc_temp.c_cc[VSTOP] = -1;
  148. #endif _POSIX_SOURCE
  149. #ifdef UNIX_BSD4_2
  150.         ltc_temp.t_suspc = ltc_temp.t_dsuspc = -1;
  151. #endif UNIX_BSD4_2
  152. #ifndef _POSIX_SOURCE
  153.         ltc_temp.t_rprntc = ltc_temp.t_flushc = -1;
  154.         ltc_temp.t_werasc = ltc_temp.t_lnextc = -1;
  155.         tc_temp.t_startc = tc_temp.t_stopc = -1;
  156. #endif _POSIX_SOURCE
  157.     }
  158. #ifdef _POSIX_SOURCE
  159.        tcsetattr(0,TCSANOW,&tc_temp);
  160. #else
  161.     ioctl(0, TIOCSETC, &tc_temp);
  162.     ioctl(0, TIOCSLTC, <c_temp);
  163. #endif
  164. }
  165.  
  166. /* md_heed_signals():
  167.  *
  168.  * This routine tells the program to call particular routines when
  169.  * certain interrupts/events occur:
  170.  *
  171.  *      SIGINT: call onintr() to interrupt fight with monster or long rest.
  172.  *      SIGQUIT: call byebye() to check for game termination.
  173.  *      SIGHUP: call error_save() to save game when terminal hangs up.
  174.  *
  175.  *        On VMS, SIGINT and SIGQUIT correspond to ^C and ^Y.
  176.  *
  177.  * This routine is not strictly necessary and can be stubbed.  This will
  178.  * mean that the game cannot be interrupted properly with keyboard
  179.  * input, this is not usually critical.
  180.  */
  181.  
  182. md_heed_signals()
  183. {
  184.     signal(SIGINT, onintr);
  185.     signal(SIGQUIT, byebye);
  186.     signal(SIGHUP, error_save);
  187. }
  188.  
  189. /* md_ignore_signals():
  190.  *
  191.  * This routine tells the program to completely ignore the events mentioned
  192.  * in md_heed_signals() above.  The event handlers will later be turned on
  193.  * by a future call to md_heed_signals(), so md_heed_signals() and
  194.  * md_ignore_signals() need to work together.
  195.  *
  196.  * This function should be implemented or the user risks interrupting
  197.  * critical sections of code, which could cause score file, or saved-game
  198.  * file, corruption.
  199.  */
  200.  
  201. md_ignore_signals()
  202. {
  203.     signal(SIGQUIT, SIG_IGN);
  204.     signal(SIGINT, SIG_IGN);
  205.     signal(SIGHUP, SIG_IGN);
  206.     signal(SIGTSTP,SIG_IGN);    /* No ^Z ! */
  207. }
  208.  
  209. /* md_get_file_id():
  210.  *
  211.  * This function returns an integer that uniquely identifies the specified
  212.  * file.  It need not check for the file's existence.  In UNIX, the inode
  213.  * number is used.
  214.  *
  215.  * This function need not be implemented.  To stub the routine, just make
  216.  * it return 0.  This will make the game less able to prevent users from
  217.  * modifying saved-game files.  This is probably no big deal.
  218.  */
  219.  
  220. int
  221. md_get_file_id(fname)
  222. char *fname;
  223. {
  224.     struct stat sbuf;
  225.  
  226.     if (stat(fname, &sbuf)) {
  227.         return(-1);
  228.     }
  229.     return((int) sbuf.st_ino);
  230. }
  231.  
  232. /* md_link_count():
  233.  *
  234.  * This routine returns the number of hard links to the specified file.
  235.  *
  236.  * This function is not strictly necessary.  On systems without hard links
  237.  * this routine can be stubbed by just returning 1.
  238.  */
  239.  
  240. int
  241. md_link_count(fname)
  242. char *fname;
  243. {
  244.     struct stat sbuf;
  245.  
  246.     stat(fname, &sbuf);
  247.     return((int) sbuf.st_nlink);
  248. }
  249.  
  250. /* md_gct(): (Get Current Time)
  251.  *
  252.  * This function returns the current year, month(1-12), day(1-31), hour(0-23),
  253.  * minute(0-59), and second(0-59).  This is used for identifying the time
  254.  * at which a game is saved.
  255.  *
  256.  * This function is not strictly necessary.  It can be stubbed by returing
  257.  * zeros instead of the correct year, month, etc.  If your operating
  258.  * system doesn't provide all of the time units requested here, then you
  259.  * can provide only those that it does, and return zeros for the others.
  260.  * If you cannot provide good time values, then users may be able to copy
  261.  * saved-game files and play them.  
  262.  */
  263.  
  264. md_gct(rt_buf)
  265. struct rogue_time *rt_buf;
  266. {
  267.     struct timeval tv;
  268.     struct timezone tzp;
  269.     struct tm *t;
  270.     long seconds;
  271.  
  272.     gettimeofday(&tv, &tzp);
  273.     seconds = (long) tv.tv_sec;
  274.     t = localtime(&seconds);
  275.  
  276.     rt_buf->year = t->tm_year;
  277.     rt_buf->month = t->tm_mon + 1;
  278.     rt_buf->day = t->tm_mday;
  279.     rt_buf->hour = t->tm_hour;
  280.     rt_buf->minute = t->tm_min;
  281.     rt_buf->second = t->tm_sec;
  282. }
  283.  
  284. /* md_gfmt: (Get File Modification Time)
  285.  *
  286.  * This routine returns a file's date of last modification in the same format
  287.  * as md_gct() above.
  288.  *
  289.  * This function is not strictly necessary.  It is used to see if saved-game
  290.  * files have been modified since they were saved.  If you have stubbed the
  291.  * routine md_gct() above by returning constant values, then you may do
  292.  * exactly the same here.
  293.  * Or if md_gct() is implemented correctly, but your system does not provide
  294.  * file modification dates, you may return some date far in the past so
  295.  * that the program will never know that a saved-game file being modified.  
  296.  * You may also do this if you wish to be able to restore games from
  297.  * saved-games that have been modified.
  298.  */
  299.  
  300. md_gfmt(fname, rt_buf)
  301. char *fname;
  302. struct rogue_time *rt_buf;
  303. {
  304.     struct stat sbuf;
  305.     long seconds;
  306.     struct tm *t;
  307.  
  308.     stat(fname, &sbuf);
  309.     seconds = (long) sbuf.st_mtime;
  310.     t = localtime(&seconds);
  311.  
  312.     rt_buf->year = t->tm_year;
  313.     rt_buf->month = t->tm_mon + 1;
  314.     rt_buf->day = t->tm_mday;
  315.     rt_buf->hour = t->tm_hour;
  316.     rt_buf->minute = t->tm_min;
  317.     rt_buf->second = t->tm_sec;
  318. }
  319.  
  320. /* md_df: (Delete File)
  321.  *
  322.  * This function deletes the specified file, and returns true (1) if the
  323.  * operation was successful.  This is used to delete saved-game files
  324.  * after restoring games from them.
  325.  *
  326.  * Again, this function is not strictly necessary, and can be stubbed
  327.  * by simply returning 1.  In this case, saved-game files will not be
  328.  * deleted and can be replayed.
  329.  */
  330.  
  331. boolean
  332. md_df(fname)
  333. char *fname;
  334. {
  335.     if (unlink(fname)) {
  336.         return(0);
  337.     }
  338.     return(1);
  339. }
  340.  
  341. /* md_gln: (Get login name)
  342.  *
  343.  * This routine returns the login name of the user.  This string is
  344.  * used mainly for identifying users in score files.
  345.  *
  346.  * A dummy string may be returned if you are unable to implement this
  347.  * function, but then the score file would only have one name in it.
  348.  */
  349.  
  350. char *
  351. md_gln()
  352. {
  353.     char *getlogin();
  354.     char *t;
  355.     t = getlogin();
  356.     return(t);
  357. }
  358.  
  359. /* md_sleep:
  360.  *
  361.  * This routine causes the game to pause for the specified number of
  362.  * seconds.
  363.  *
  364.  * This routine is not necessary at all, and can be stubbed with no ill
  365.  * effects.
  366.  */
  367.  
  368. md_sleep(nsecs)
  369. int nsecs;
  370. {
  371.     (void) sleep(nsecs);
  372. }
  373.  
  374. /* md_getenv()
  375.  *
  376.  * This routine gets certain values from the user's environment.  These
  377.  * values are strings, and each string is identified by a name.  The names
  378.  * of the values needed, and their use, is as follows:
  379.  *
  380.  *   TERMCAP
  381.  *     The name of the users's termcap file, NOT the termcap entries
  382.  *     themselves.  This is used ONLY if the program is compiled with
  383.  *     CURSES defined (-DCURSES).  Even in this case, the program need
  384.  *     not find a string for TERMCAP.  If it does not, it will use the
  385.  *     default termcap file as returned by md_gdtcf();
  386.  *   TERM
  387.  *     The name of the users's terminal.  This is used ONLY if the program
  388.  *     is compiled with CURSES defined (-DCURSES).  In this case, the string
  389.  *     value for TERM must be found, or the routines in curses.c cannot
  390.  *     function, and the program will quit.
  391.  *   ROGUEOPTS
  392.  *     A string containing the various game options.  This need not be
  393.  *     defined.
  394.  *   HOME
  395.  *     The user's home directory.  This is only used when the user specifies
  396.  *     '~' as the first character of a saved-game file.  This string need
  397.  *     not be defined.
  398.  *
  399.  * If your system does not provide a means of searching for these values,
  400.  * you will have to do it yourself.  None of the values above really need
  401.  * to be defined except TERM when the program is compiled with CURSES
  402.  * defined.  In this case, as a bare minimum, you can check the 'name'
  403.  * parameter, and if it is "TERM" find the terminal name and return that,
  404.  * else return zero.  If the program is not compiled with CURSES, you can
  405.  * get by with simply always returning zero.  Returning zero indicates
  406.  * that their is no defined value for the given string.
  407.  */
  408.  
  409. char *
  410. md_getenv(name)
  411. char *name;
  412. {
  413.     char *value;
  414.     char *getenv();
  415.  
  416.     value = getenv(name);
  417.  
  418.     return(value);
  419. }
  420.  
  421. /* md_malloc()
  422.  *
  423.  * This routine allocates, and returns a pointer to, the specified number
  424.  * of bytes.  This routines absolutely MUST be implemented for your
  425.  * particular system or the program will not run at all.  Return zero
  426.  * when no more memory can be allocated.
  427.  */
  428.  
  429. char *
  430. md_malloc(n)
  431. int n;
  432. {
  433.     char *malloc();
  434.     char *t;
  435.  
  436.     t = malloc(n);
  437.     return(t);
  438. }
  439.  
  440. /* md_gseed() (Get Seed)
  441.  *
  442.  * This function returns a seed for the random number generator (RNG).  This
  443.  * seed causes the RNG to begin generating numbers at some point in it's
  444.  * sequence.  Without a random seed, the RNG will generate the same set
  445.  * of numbers, and every game will start out exactly the same way.  A good
  446.  * number to use is the process id, given by getpid() on most UNIX systems.
  447.  *
  448.  * You need to find some single random integer, such as:
  449.  *   process id.
  450.  *   current time (minutes + seconds) returned from md_gct(), if implemented.
  451.  *   
  452.  * It will not help to return "get_rand()" or "rand()" or the return value of
  453.  * any pseudo-RNG.  If you cannot a random number, you can just return 1,
  454.  * but this means you games will ALWAYS start the same way, and will play
  455.  * exactly the same way given the same input.
  456.  */
  457.  
  458. md_gseed()
  459. {
  460.     return(getpid());
  461. }
  462.  
  463. /* md_exit():
  464.  *
  465.  * This function causes the program to discontinue execution and exit.
  466.  * This function must be implemented or the program will continue to
  467.  * hang when it should quit.
  468.  */
  469.  
  470. md_exit(status)
  471. int status;
  472. {
  473.     exit(status);
  474. }
  475.  
  476. /* If you have a viable curses/termlib library, then use it and don't bother
  477.  * implementing the routines below.  And don't compile with -DCURSES.
  478.  */
  479.  
  480. #ifdef CURSES
  481.  
  482. /* md_cbreak_no_echo_nonl:
  483.  *
  484.  * This routine sets up some terminal characteristics.  The tty-driver
  485.  * must be told to:
  486.  *   1.)  Not echo input.
  487.  *   2.)  Transmit input characters immediately upon typing. (cbreak mode)
  488.  *   3.)  Move the cursor down one line, without changing column, and
  489.  *        without generating a carriage-return, when it
  490.  *        sees a line-feed.  This is only necessary if line-feed is ever
  491.  *        used in the termcap 'do' (cursor down) entry, in which case,
  492.  *        your system should must have a way of accomplishing this.
  493.  *
  494.  * When the parameter 'on' is true, the terminal is set up as specified
  495.  * above.  When this parameter is false, the terminal is restored to the
  496.  * original state.
  497.  *
  498.  * Raw mode should not to be used.  Keyboard signals/events/interrupts should
  499.  * be sent, although they are not strictly necessary.  See notes in
  500.  * md_heed_signals().
  501.  *
  502.  * This function must be implemented for rogue to run properly if the
  503.  * program is compiled with CURSES defined to use the enclosed curses
  504.  * emulation package.  If you are not using this, then this routine is
  505.  * totally unnecessary.
  506.  * 
  507.  * Notice that information is saved between calls.  This is used to
  508.  * restore the terminal to an initial saved state.
  509.  *
  510.  */
  511.  
  512. md_cbreak_no_echo_nonl(on)
  513. boolean on;
  514. {
  515. #ifdef _POSIX_SOURCE
  516.     struct termios tty_buf ;
  517.     static struct termios save_buf ;
  518. #else
  519.     struct sgttyb tty_buf;
  520.     int tty_save_flags;
  521. #endif _POSIX_SOURCE
  522.  
  523.     if (on) 
  524.          {
  525. #ifdef _POSIX_SOURCE
  526.         tcgetattr(0,&tty_buf);    
  527.         tcgetattr(0,&save_buf);    
  528.     tty_buf.c_iflag |= ICRNL ;
  529.     tty_buf.c_iflag &= ~( IGNCR | INLCR ) ;
  530.     tty_buf.c_lflag &= ~(ICANON | ECHO) ;
  531.     tty_buf.c_oflag &= ~(OPOST);
  532.         tty_buf.c_cc[VMIN] = 1;
  533.         tty_buf.c_cc[VTIME] = 0; 
  534.     tcsetattr(0,TCSANOW,&tty_buf);
  535. #else
  536.     ioctl(0, TIOCGETP, &tty_buf);
  537.     tty_save_flags = tty_buf.sg_flags;
  538.     tty_buf.sg_flags |= CBREAK;
  539.     tty_buf.sg_flags &= ~(ECHO | CRMOD); /* CRMOD: see note above */
  540.         ioctl(0, TIOCSETP, &tty_buf);
  541. #endif _POSIX_SOURCE
  542.     }
  543.          else 
  544.         {
  545. #ifdef _POSIX_SOURCE
  546.     tcsetattr(0,TCSANOW,&save_buf);
  547.         exit (0);
  548. #else
  549.     tty_buf.sg_flags = tty_save_flags;
  550.     ioctl(0, TIOCSETP, &tty_buf);
  551. #endif 
  552.       }
  553. }
  554.  
  555. /* md_gdtcf(): (Get Default Termcap File)
  556.  *
  557.  * This function is called ONLY when the program is compiled with CURSES
  558.  * defined.  If you use your system's curses/termlib library, this function
  559.  * won't be called.  On most UNIX systems, "/etc/termcap" suffices.
  560.  *
  561.  * If their is no such termcap file, then return 0, but in that case, you
  562.  * must have a TERMCAP file returned from md_getenv("TERMCAP").  The latter
  563.  * will override the value returned from md_gdtcf().  If the program is
  564.  * compiled with CURSES defined, and md_gdtcf() returns 0, and
  565.  * md_getenv("TERMCAP") returns 0, the program will have no terminal
  566.  * capability information and will quit.
  567.  */
  568.  
  569. char *
  570. md_gdtcf()
  571. {
  572.     return("/etc/termcap");
  573. }
  574.  
  575. /* md_tstp():
  576.  *
  577.  * This function puts the game to sleep and returns to the shell.  This
  578.  * only applies to UNIX 4.2 and 4.3.  For other systems, the routine should
  579.  * be provided as a do-nothing routine.  md_tstp() will only be referenced
  580.  * in the code when compiled with CURSES defined.
  581.  *
  582.  */
  583.  
  584. md_tstp()
  585. {
  586. #ifdef UNIX_BSD4_2
  587.     kill(0, SIGTSTP);
  588. #endif UNIX_BSD4_2
  589. }
  590.  
  591. #endif CURSES
  592.  
  593. #endif UNIX
  594.